package com.qfedu.edu.filter;

import com.alibaba.fastjson.JSON;
import com.qfedu.edu.bo.SecurityUser;
import com.qfedu.edu.context.Context;
import com.qfedu.edu.enum1.ResponseCode;
import com.qfedu.edu.result.R;
import com.qfedu.edu.utils.HttpResponseUtils;
import com.qfedu.edu.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;

import org.framework.edu.service.TokenService;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class LoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;
    private TokenService tokenService;


    public LoginFilter(AuthenticationManager authenticationManager,TokenService tokenService){
        this.authenticationManager=authenticationManager;
        this.tokenService=tokenService;
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/user/login", HttpMethod.POST.name()));
    }

    /**
     * 登录时系统调用attemtAuthentication
     * @param request from which to extract parameters and perform the authentication
     * @param response the response, which may be needed if the implementation has to do a
     * redirect as part of a multi-stage authentication process (such as OpenID).
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                    getUsernameAndPasswordWrapObject(request);
            return authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        } catch (IOException e) {
            log.error("封装用户信息出错：{}",e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 从前端数据中获取用户名和密码封装成对象
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getUsernameAndPasswordWrapObject(HttpServletRequest request) throws IOException {
        ServletInputStream inputStream = request.getInputStream();
        byte[] buf=new byte[1024];
        int readlength = inputStream.read(buf);
        String strJson = new String(buf, 0, readlength, "utf-8");
        LoginVo loginVo = JSON.parseObject(strJson, LoginVo.class);

        return new UsernamePasswordAuthenticationToken(strJson,loginVo.getPassword());
    }

    /**
     * 登录成功的回调方法
     * @param request
     * @param response
     * @param chain
     * @param authResult the object returned from the <tt>attemptAuthentication</tt>
     * method.
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        SecurityUser securityUser  = (SecurityUser) authResult.getPrincipal();
        String token = tokenService.createToken(securityUser.getUser().getUserId(), securityUser.getUsername());
        //放到上下文
        Context.getRoleAndPerm().put(token,securityUser.getRoleAndPermList());

        R r = R.ok().data("token", token).data("userId", securityUser.getUser().getUserId()).data("username",
                securityUser.getUsername());

        HttpResponseUtils.sendResponse(response, r);
        log.info("登录成功");
    }

    /**
     * 登录失败的回调方法
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        R error = R.error(ResponseCode.LOGIN_EXCEPTION);
        HttpResponseUtils.sendResponse(response,error);
        log.info("登录失败");
    }
}
